#pragma once

#include "Core.h"

class Url
{
public:
    std::wstring hostName, urlPath, scheme;
    INTERNET_PORT port;

    Url(const std::wstring &url)
    {
        URL_COMPONENTS urlComp = {0};
        urlComp.dwStructSize = sizeof(urlComp);
        urlComp.dwSchemeLength    = -1;
        urlComp.dwHostNameLength  = -1;
        urlComp.dwUrlPathLength   = -1;
        urlComp.dwExtraInfoLength = -1;
        WinHttpCrackUrl(url.c_str(), DWORD(url.size()), 0, &urlComp);
        
        hostName = wstring(urlComp.lpszHostName, urlComp.dwHostNameLength);
        urlPath = wstring(urlComp.lpszUrlPath, urlComp.dwUrlPathLength);
        scheme = wstring(urlComp.lpszScheme, urlComp.dwSchemeLength);
        port = urlComp.nPort;
    }

    bool Https() const { return scheme == L"https"; }
};

inline wchar_t Digit(int n)
{
    if (n < 10) return L'0' + n;
    else return 'a' + n - 10;
}

inline std::wstring UrlEncode(const std::wstring &s)
{
    std::wstring e;
    for (size_t i = 0; i < s.size(); i++) {
        if (isalnum(s[i])) {
            e += s[i];
        }
        else {
            e += L'%';
            e += Digit((s[i] >> 4) & 0xF);
            e += Digit(s[i] & 0xF);
        }
    }
    return e;
}

class HttpReq
{
    HINTERNET hSession, hConnect;
    Url url_;

public:
    std::vector<char> respData_;
    DWORD respStatusCode_;

    HttpReq(const std::wstring &url) : url_(url), respStatusCode_(0)
    {
        hSession = WinHttpOpen( L"Quickwrite/1.0",  
            WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
            WINHTTP_NO_PROXY_NAME, 
            WINHTTP_NO_PROXY_BYPASS, 0);
        if (hSession) {
            hConnect = WinHttpConnect(hSession, url_.hostName.c_str(), url_.port, 0);
        }
    }

    ~HttpReq()
    {
        if (hConnect) WinHttpCloseHandle(hConnect);
        if (hSession) WinHttpCloseHandle(hSession);
    }

    void Post(const std::wstring &wbody, const std::wstring &headers = std::wstring())
    {
        DWORD dwSize = 0;
        DWORD dwDownloaded = 0;
        BOOL  bResults = FALSE;
        HINTERNET  hRequest = NULL;

        std::string body(wbody.begin(), wbody.end());

        hRequest = WinHttpOpenRequest( hConnect, L"POST", url_.urlPath.c_str(),
                                       NULL, WINHTTP_NO_REFERER, 
                                       WINHTTP_DEFAULT_ACCEPT_TYPES, 
                                       url_.Https() ? WINHTTP_FLAG_SECURE : 0);

        if (hRequest)
            bResults = WinHttpAddRequestHeaders(hRequest, headers.c_str(), DWORD(headers.size()),
                WINHTTP_ADDREQ_FLAG_ADD|WINHTTP_ADDREQ_FLAG_REPLACE);

        if (bResults)
            bResults = WinHttpSendRequest( hRequest,
                                           WINHTTP_NO_ADDITIONAL_HEADERS , 0,
                                           LPVOID(body.c_str()), DWORD(body.size()), 
                                           DWORD(body.size()), 0);

        if (bResults)
            bResults = WinHttpReceiveResponse( hRequest, NULL);

        respData_.clear();
        if (bResults)
            do {
                dwSize = 0;
                WinHttpQueryDataAvailable( hRequest, &dwSize);
                if (dwSize > 0) {
                    respData_.insert(respData_.end(), dwSize, 0);
                    WinHttpReadData(hRequest, &*(respData_.end() - dwSize), dwSize, &dwDownloaded);
                }
            } while (dwSize>0);

        DWORD len = 4;
        WinHttpQueryHeaders(
            hRequest,
            WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER,
            WINHTTP_HEADER_NAME_BY_INDEX,
            &respStatusCode_, &len,
            WINHTTP_NO_HEADER_INDEX);

        if (hRequest) WinHttpCloseHandle(hRequest);
    }
};
